package listeners

import (
	"blockchains-aio/conf"
	"blockchains-aio/db"
	"blockchains-aio/stack"
	"blockchains-aio/util"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"os"
	"strconv"
)

// latest pos and pos2 support
func RegisterStack2ForPos(router *gin.Engine) {
	// temporal
	//router.POST("/stack2/pos", doDockStack2DeployForPos)

	//-----pos2 consensus as followed
	router.POST("/stack2/tmpl/pos", doGenStack2ConfigForPos)
	router.POST("/stack2/pos", doDockStack2DeployForPos2)

}

func doGenStack2ConfigForPos(ctx *gin.Context) {
	var config stack.SoloPOS2
	consensus := ctx.GetHeader("Consensus-Template-Type") //ns3pos2

	if err := ctx.BindJSON(&config); err != nil {
		ctx.JSON(http.StatusBadRequest, err)
		return
	}
	config.Nfs, _ = util.ExpandTilde(conf.GetNfsFolder())

	pos2Tmpl := fmt.Sprintf("%s/%s.tmpl", conf.GetStackTemplateFolder(), consensus)
	expendedPoaTmpl, _ := util.ExpandTilde(pos2Tmpl)
	err := stack.ParsePOS2Template(ctx.Writer, expendedPoaTmpl, config)
	if err != nil {
		//ctx.JSON(http.StatusBadRequest, fmt.Sprintf("%v", err))
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(Stack, 1, "doGenStack2ConfigForPos", fmt.Sprintf("%v", err)).Json())
	}
}

func doDockStack2DeployForPos2(ctx *gin.Context) {
	chainname := ctx.PostForm("chainname")
	nodeNum := ctx.PostForm("nodeNum")
	consensus := ctx.PostForm("consensus")

	log.Printf("recieved {chainname:%s,nodeNum:%s,consensus:%s}", chainname, nodeNum, consensus)

	if len(chainname) == 0 || len(nodeNum) == 0 {
		//ctx.JSON(400, fmt.Sprintf("Failed to get chainname or nodeNum"))
		ctx.JSON(400, NewErrorMessage(Stack, 1, "doDockStack2DeployForPos2", fmt.Sprintf("Failed to get chainname or nodeNum")).Json())
		return
	}
	if _, err := strconv.Atoi(nodeNum); err != nil {
		//ctx.JSON(400, fmt.Sprintf("%v is not a number", nodeNum))
		ctx.JSON(400, NewErrorMessage(Stack, 2, "doDockStack2DeployForPos2", fmt.Sprintf("%v is not a number", nodeNum)).Json())
		return
	}
	nodeNumber, _ := strconv.Atoi(nodeNum)
	if len(consensus) == 0 {
		consensus = "pos2"
	}

	file, _ := ctx.FormFile("file")
	f, err := file.Open()
	if err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to open yaml:%v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 3, "doDockStack2DeployForPos2", fmt.Sprintf("Failed to open yaml:%v", err)).Json())
		return
	}
	defer f.Close()

	p := make([]byte, file.Size)
	if _, err := f.Read(p); err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to read yaml: %v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 4, "doDockStack2DeployForPos2", fmt.Sprintf("Failed to read yaml: %v", err)).Json())
		return
	}

	if err := stack.MkChainDirAndCopyDirs_POS2(chainname, consensus); err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to copy dirs: %v", err))
		ctx.JSON(400, NewErrorMessage(Stack, 5, "doDockStack2DeployForPos2", fmt.Sprintf("Failed to copy dirs: %v", err)).Json())
		return
	}

	chainFolder, _ := util.ExpandTilde(fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chainname))
	//yaml := chainFolder + "/" + chainname + ".yml"
	yaml := chainFolder + "/" + conf.DefaultComposeFileName

	if err := os.WriteFile(yaml, p, 0644); err != nil {
		// ctx.JSON(400, fmt.Sprintf("Failed to write file %s: %v", yaml, err))
		ctx.JSON(400, NewErrorMessage(Stack, 6, "doDockStack2DeployForPos2", fmt.Sprintf("Failed to write file %s: %v", yaml, err)).Json())
		return
	}

	log.Printf(fmt.Sprintf("working directory: %s", chainFolder))
	out, err := util.DockerComposeDeployUpConfigFile(yaml, chainFolder)
	if err != nil {
		//ctx.JSON(400, fmt.Sprintf("Failed to deploy stack: %v", err))
		ctx.JSON(http.StatusInternalServerError, NewErrorMessage(Stack, conf.BrindDownContainersInCompose, "doDockStack2DeployForPos", fmt.Sprintf("Failed to deploy stack: %v", err)).Json())
		return
	}

	if err = db.CreateStack(chainname, consensus, string(p), nodeNumber); err != nil {
		//ctx.JSON(http.StatusBadRequest, fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), nodeNumber, err))
		ctx.JSON(http.StatusBadRequest, NewErrorMessage(Stack, 7, "doDockStack2DeployForPos", fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), nodeNumber, err)).Json())
		return
	}

	ctx.JSON(200, string(out))
}

// old-rusted,deprecated
//func doDockStack2DeployForPos(ctx *gin.Context) {
//
//	chainname := ctx.PostForm("chainname")
//	nodeNum := ctx.PostForm("nodeNum")
//	consensus := ctx.PostForm("consensus")
//
//	log.Printf("recieved {chainname:%s,nodeNum:%s,consensus:%s}", chainname, nodeNum, consensus)
//
//	if len(chainname) == 0 || len(nodeNum) == 0 {
//		//ctx.JSON(400, fmt.Sprintf("Failed to get chainname or nodeNum"))
//		ctx.JSON(400, NewErrorMessage(Stack, 4, "doDockStack2DeployForPos", fmt.Sprintf("Failed to get chainname or nodeNum")).Json())
//		return
//	}
//	if _, err := strconv.Atoi(nodeNum); err != nil {
//		ctx.JSON(400, fmt.Sprintf("%v is not a number", nodeNum))
//		return
//	}
//	nodeNumber, _ := strconv.Atoi(nodeNum)
//	if len(consensus) == 0 {
//		consensus = "poa"
//	}
//
//	file, _ := ctx.FormFile("file")
//	f, err := file.Open()
//	if err != nil {
//		ctx.JSON(400, fmt.Sprintf("Failed to open yaml:%v", err))
//		return
//	}
//	defer f.Close()
//
//	p := make([]byte, file.Size)
//	if _, err := f.Read(p); err != nil {
//		ctx.JSON(400, fmt.Sprintf("Failed to read yaml: %v", err))
//		return
//	}
//
//	if err := stack.CopyDirs_POA2(chainname, consensus); err != nil {
//		ctx.JSON(400, fmt.Sprintf("Failed to copy dirs: %v", err))
//		return
//	}
//
//	if err := stack.BuildPow2NodesDir(nodeNumber, chainname, consensus); err != nil {
//		ctx.JSON(400, fmt.Sprintf("Failed to copy dirs: %v", err))
//		return
//	}
//
//	chainFolder, _ := util.ExpandTilde(fmt.Sprintf("%s/%s", conf.GetNfsFolder(), chainname))
//	//yaml := chainFolder + "/" + chainname + ".yml"
//	yaml := chainFolder + "/" + conf.DefaultComposeFileName
//
//	if err := os.WriteFile(yaml, p, 0644); err != nil {
//		ctx.JSON(400, fmt.Sprintf("Failed to write file %s: %v", yaml, err))
//		return
//	}
//
//	log.Printf(fmt.Sprintf("working directory: %s", chainFolder))
//	out, err := util.DockerComposeDeployUpConfigFile(yaml, chainFolder)
//	if err != nil {
//		//ctx.JSON(400, fmt.Sprintf("Failed to deploy stack: %v", err))
//		ctx.JSON(http.StatusInternalServerError, NewErrorMessage(Stack, conf.BrindDownContainersInCompose, "doDockStack2DeployForPos", fmt.Sprintf("Failed to deploy stack: %v", err)).Json())
//		return
//	}
//
//	if err = db.CreateStack(chainname, consensus, string(p), nodeNumber); err != nil {
//		//ctx.JSON(http.StatusBadRequest, fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), nodeNumber, err))
//		ctx.JSON(http.StatusBadRequest, NewErrorMessage(Stack, 1, "doDockStack2DeployForPos", fmt.Sprintf("Failed to store the stack{chainname:%s, consensus:%s, config:%s, nodeNumber:%v}: %v", chainname, consensus, string(p), nodeNumber, err)).Json())
//		return
//	}
//
//	ctx.JSON(200, string(out))
//}
